
#include <cstdio>
#include <BBuffer>
#include <BUdpSocket>
#include "member_BSocket.h"
#include "member_BUdpSocket.h"

using namespace BWE;

#define member					(*(member_BUdpSocket*)_ptr)
#define member_allocate()		_ptr = new member_BUdpSocket(this)
#define member_release()		delete (member_BUdpSocket*)_ptr

#ifdef linux
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

BUdpSocket::BUdpSocket()
{
	member_allocate();
	socket_member(this)->sock = ::socket(AF_INET, SOCK_DGRAM, 0);
}
BUdpSocket::~BUdpSocket()
{
	member_release();
}

BUdpSocket::Type BUdpSocket::type() const
{
	return UdpSocket;
}

bool BUdpSocket::bind(const BString& ip, int port)
{
	if (socket_member(this)->sock == 0)
		socket_member(this)->sock = ::socket(AF_INET, SOCK_DGRAM, 0);

	if (socket_member(this)->sock == 0)
		return false;
	
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip.cstr());

	int ret = ::bind(socket_member(this)->sock, (sockaddr*)&addr, sizeof(addr));
	if (ret == -1)
	{
		perror("bind");
		char* errStr = strerror(errno);
		member.errorStr = errStr;
		this->emit(Signal_Error, errStr);
		return false;
	}
	
	socket_member(this)->state = State_Listening;
	return true;
}

int BUdpSocket::sendTo(const BString& ip, int port, const char* data, int size)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, data, size, 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}
int BUdpSocket::sendTo(const BString& ip, int port, const BByteArray& bytes)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, (const char*)bytes.data(), bytes.size(), 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}
int BUdpSocket::sendTo(const BString& ip, int port, const BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, (const char*)buffer.data(), buffer.size(), 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}
int BUdpSocket::sendTo(const BString& ip, int port, const BString& text)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, (const char*)text.cstr(), text.size(), 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}

int BUdpSocket::recvFrom(const BString& ip, int port, char* data, int& size)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());
	socklen_t from_addr_len = sizeof(sockaddr_in);

	int len = ::recvfrom(socket_member(this)->sock, data, size, 0, (sockaddr*)&to_addr, &from_addr_len);
	return true;
}
int BUdpSocket::recvFrom(const BString& ip, int port, BByteArray& bytes)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());
	socklen_t from_addr_len = sizeof(sockaddr_in);

	int size = 0;
	while (1)
	{
		BByte data[1024];
		int ret = ::recvfrom(socket_member(this)->sock, (char*)data, 1024, 0, (sockaddr*)&to_addr, &from_addr_len);
		if (ret == -1)
		{
			socket_member(this)->checkError();
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret == 0)
		{
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret > 0)
		{
			bytes.append(data, ret);
			size += ret;
		}
		if (ret < 1024)
		{
			break;
		}
	}
	return size;
}
int BUdpSocket::recvFrom(const BString& ip, int port, BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());
	socklen_t from_addr_len = sizeof(sockaddr_in);

	int size = 0;
	while (1)
	{
		BByte data[1024];
		int ret = ::recvfrom(socket_member(this)->sock, (char*)data, 1024, 0, (sockaddr*)&to_addr, &from_addr_len);
		if (ret == -1)
		{
			socket_member(this)->checkError();
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret == 0)
		{
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret > 0)
		{
			buffer.write(data, ret);
			size += ret;
		}
		if (ret < 1024)
		{
			break;
		}
	}
	return size;
}
int BUdpSocket::recvFrom(const BString& ip, int port, BString& text)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.s_addr = inet_addr(ip.cstr());
	socklen_t from_addr_len = sizeof(sockaddr_in);

	int size = 0;
	while (1)
	{
		char data[1024];
		int ret = ::recvfrom(socket_member(this)->sock, data, 1024, 0, (sockaddr*)&to_addr, &from_addr_len);
		if (ret == -1)
		{
			socket_member(this)->checkError();
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret == 0)
		{
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret > 0)
		{
			text.append(data, 0, ret);
			size += ret;
		}
		if (ret < 1024)
		{
			break;
		}
	}
	return size;
}

int BUdpSocket::recv(char* data, int length)
{
	if (socket_member(this)->sock == 0)
		return -1;
	if (!data || length < 1)
		return 0;
	int ret = ::recv(socket_member(this)->sock, data, length, 0);
	if (ret == -1)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return 0;
	}
	if (ret == 0)
	{
		this->close();
	}
	return ret;
}
int BUdpSocket::recv(BByteArray& bytes)
{
	if (socket_member(this)->sock == 0)
		return -1;
	int ret = ::recv(socket_member(this)->sock, (char*)bytes.data(), bytes.size(), 0);
	if (ret == -1)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	if (ret == 0)
	{
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	return ret;
}
int BUdpSocket::recv(BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;
	int ret = ::recv(socket_member(this)->sock, (char*)buffer.data(), buffer.size(), 0);
	if (ret == -1)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	if (ret == 0)
	{
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	buffer.seek(ret);
	return ret;
}
int BUdpSocket::recv(BString& text)
{
	if (socket_member(this)->sock == 0)
		return -1;
	int ret = ::recv(socket_member(this)->sock, (char*)text.cstr(), text.size(), 0);
	if (ret == -1)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	if (ret == 0)
	{
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	return ret;
}

int BUdpSocket::read(BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;
	if (member.dataSize > 0)
	{
		buffer.seek(0);
		buffer.write(member.buffer.data(), member.dataSize);
		return member.dataSize;
	}
	return 0;
}


#endif

#ifdef _WIN32

BUdpSocket::BUdpSocket()
{
	member_allocate();
	socket_member(this)->sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
BUdpSocket::~BUdpSocket()
{
	member_release();
}

BUdpSocket::Type BUdpSocket::type() const
{
	return UdpSocket;
}

bool BUdpSocket::bind(const BString& ip, int port)
{
	if (socket_member(this)->sock == 0)
		socket_member(this)->sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

	if (socket_member(this)->sock == 0)
		return false;

	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	InetPtonA(AF_INET, ip.cstr(), &addr.sin_addr.s_addr);

	int ret = ::bind(socket_member(this)->sock, (sockaddr*)&addr, sizeof(addr));
	if (ret == SOCKET_ERROR)
	{
		socket_member(this)->checkError();
		if (socket_member(this)->errorStr)
			perror(socket_member(this)->errorStr);
		return false;
	}
	socket_member(this)->state = State_Listening;
	return true;
}

int BUdpSocket::sendTo(const BString& ip, int port, const char* data, int size)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, data, size, 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}
int BUdpSocket::sendTo(const BString& ip, int port, const BByteArray& bytes)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, (const char*)bytes.data(), bytes.size(), 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}
int BUdpSocket::sendTo(const BString& ip, int port, const BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, (const char*)buffer.data(), buffer.size(), 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}
int BUdpSocket::sendTo(const BString& ip, int port, const BString& text)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, (const char*)text.cstr(), text.size(), 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return -1;
}

int BUdpSocket::recvFrom(const BString& ip, int port, char* data, int& size)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());
	int from_addr_len = sizeof(sockaddr_in);

	int len = ::recvfrom(socket_member(this)->sock, data, size, 0, (sockaddr*)&to_addr, &from_addr_len);
	return true;
}
int BUdpSocket::recvFrom(const BString& ip, int port, BByteArray& bytes)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());
	int from_addr_len = sizeof(sockaddr_in);

	int size = 0;
	while (1)
	{
		BByte data[1024];
		int ret = ::recvfrom(socket_member(this)->sock, (char*)data, 1024, 0, (sockaddr*)&to_addr, &from_addr_len);
		if (ret == SOCKET_ERROR)
		{
			socket_member(this)->checkError();
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret == 0)
		{
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret > 0)
		{
			bytes.append(data, ret);
			size += ret;
		}
		if (ret < 1024)
		{
			break;
		}
	}
	return size;
}
int BUdpSocket::recvFrom(const BString& ip, int port, BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());
	int from_addr_len = sizeof(sockaddr_in);

	int size = 0;
	while (1)
	{
		BByte data[1024];
		int ret = ::recvfrom(socket_member(this)->sock, (char*)data, 1024, 0, (sockaddr*)&to_addr, &from_addr_len);
		if (ret == SOCKET_ERROR)
		{
			socket_member(this)->checkError();
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret == 0)
		{
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret > 0)
		{
			buffer.write(data, ret);
			size += ret;
		}
		if (ret < 1024)
		{
			break;
		}
	}
	return size;
}
int BUdpSocket::recvFrom(const BString& ip, int port, BString& text)
{
	if (socket_member(this)->sock == 0)
		return -1;

	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());
	int from_addr_len = sizeof(sockaddr_in);

	int size = 0;
	while (1)
	{
		char data[1024];
		int ret = ::recvfrom(socket_member(this)->sock, data, 1024, 0, (sockaddr*)&to_addr, &from_addr_len);
		if (ret == SOCKET_ERROR)
		{
			socket_member(this)->checkError();
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret == 0)
		{
			this->close();
			emit(Signal_Disconnected);
			break;
		}
		if (ret > 0)
		{
			text.append(data, 0, ret);
			size += ret;
		}
		if (ret < 1024)
		{
			break;
		}
	}
	return size;
}

int BUdpSocket::recv(char* data, int length)
{
	if (socket_member(this)->sock == 0)
		return -1;
	if (!data || length < 1)
		return 0;
	int ret = ::recv(socket_member(this)->sock, data, length, 0);
	if (ret == SOCKET_ERROR)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return 0;
	}
	if (ret == 0)
	{
		this->close();
	}
	return ret;
}
int BUdpSocket::recv(BByteArray& bytes)
{
	if (socket_member(this)->sock == 0)
		return -1;
	int ret = ::recv(socket_member(this)->sock, (char*)bytes.data(), bytes.size(), 0);
	if (ret == SOCKET_ERROR)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	if (ret == 0)
	{
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	return ret;
}
int BUdpSocket::recv(BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;
	int ret = ::recv(socket_member(this)->sock, (char*)buffer.data(), buffer.size(), 0);
	if (ret == SOCKET_ERROR)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	if (ret == 0)
	{
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	buffer.seek(ret);
	return ret;
}
int BUdpSocket::recv(BString& text)
{
	if (socket_member(this)->sock == 0)
		return -1;
	int ret = ::recv(socket_member(this)->sock, (char*)text.cstr(), text.size(), 0);
	if (ret == SOCKET_ERROR)
	{
		socket_member(this)->checkError();
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	if (ret == 0)
	{
		this->close();
		emit(Signal_Disconnected);
		return ret;
	}
	return ret;
}

int BUdpSocket::read(BBuffer& buffer)
{
	if (socket_member(this)->sock == 0)
		return -1;
	if (member.dataSize > 0)
	{
		buffer.seek(0);
		buffer.write(member.buffer.data(), member.dataSize);
		return member.dataSize;
	}
	return 0;
}

#endif

bool BUdpSocket::setBufferSize(int bufferSize)
{
	if (bufferSize < 0)
		return false;
	if (bufferSize == 0 && member.buffer.size())
	{
		member.buffer.clear();
		return true;
	}
	if (member.buffer.size() != bufferSize)
	{
		member.buffer.resize(bufferSize);
	}
	return true;
}
int BUdpSocket::bufferSize() const
{
	return member.buffer.size();
}


